import sys

import rust_stdf_helper
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QFileDialog,
                             QAbstractItemView, QMessageBox, QHeaderView)
from PyQt5 import QtCore, QtWidgets, QtGui, QtSql
from deps.ui.Ui_MainWindow import Ui_MainWindow
from deps.SharedSrc import *
from deps.customizedQtClass import *
Version = "V1.0.0"

from dataAnalyse.dataLoad import *


class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()

        # 主界面的设置
        self.filePathName = None  # 文件路径
        self.ui = Ui_MainWindow()
        # 主界面加载界面设置
        self.ui.setupUi(self)
        # 设置主界面的字体
        # self.loadFonts()
        # 打开文件 连接动作到槽函数
        """
        解释：为什么不写在Ui_MainWindow里面 uiMW组件是继承当前组件
        当进行一个传递后，其父类改变，所以不能在其中实现槽函数
        """
        # 设置槽函数
        self.allAction()

        # 设置应用程序的图标
        self.setQIcon()
        # 初始表格元素
        self.init_DataTable()
        # 测试项显示
        self.init_TestList()

        # 加载识别文件
        self.enableDragDrop()

        # init search-related UI  搜索按钮
        self.ui.SearchBox.textChanged.connect(self.proxyModel_list.setFilterWildcard)
        self.ui.ClearButton.clicked.connect(self.clearSearchBox)
        self.ui.tabControl.currentChanged.connect(self.onSelect)



    def init_TestList(self):

        # init model for ListView
        self.sim_list = QtGui.QStandardItemModel()
        self.proxyModel_list = QtCore.QSortFilterProxyModel()
        self.proxyModel_list.setSourceModel(self.sim_list)
        self.proxyModel_list.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
        self.ui.TestList.setModel(self.proxyModel_list)
        self.ui.TestList.setItemDelegate(StyleDelegateForTable_List(self.ui.TestList))

        # get select model and connect func to change event
        # self.selModel = self.ui.TestList.selectionModel()
        # self.selModel.selectionChanged.connect(self.onSelect)
        #
        # self.selModel_wafer = self.ui.WaferList.selectionModel()
        # self.selModel_wafer.selectionChanged.connect(self.onSelect)

    def onSelect(self):
        '''
        选择项
        This func is called when events occurred in tab, site selection, test selection and wafer(晶原) selection
        '''
        currentTab = self.ui.tabControl.currentIndex()
        # switch test/wafer selection panel when tab changed
        if currentTab == tab.Wafer:
            self.ui.Selection_stackedWidget.setCurrentIndex(1)
        else:
            self.ui.Selection_stackedWidget.setCurrentIndex(0)

        if currentTab in [tab.Bin, tab.Correlate]:
            self.ui.TestList.setDisabled(True)
            self.ui.SearchBox.setDisabled(True)
            self.ui.ClearButton.setDisabled(True)
        else:
            self.ui.TestList.setDisabled(False)
            self.ui.SearchBox.setDisabled(False)
            self.ui.ClearButton.setDisabled(False)

        if self.data_interface:
            selHeads = set(self.getCheckedHeads())
            selSites = set(self.getCheckedSites())
            selTests = set(self.getSelectedTests())

            tabChanged = currentTab != self.preTab
            (preHeads, preSites, preTests) = self.selectionTracker.setdefault(currentTab,
                                                                              (None, None, None))
            if (preHeads != selHeads or
                    preSites != selSites or
                    preTests != selTests):
                # if any changes, update current tab
                updateTab = True
                updateStat = True
            else:
                updateTab = False
                updateStat = False

            # if tab changed, must update
            # statistic table
            updateStat = updateStat or tabChanged

            if updateStat:
                self.updateStatTableContent()  # update statistic table
            if updateTab:
                self.updateTabContent()  # update tab

            self.preTab = currentTab
            # always update pre selection at last
            self.selectionTracker[currentTab] = (selHeads, selSites, selTests)
    def clearSearchBox(self):
        self.ui.SearchBox.clear()
    def init_DataTable(self):
        # file header table  info 界面
        self.tmodel_info = QtGui.QStandardItemModel()
        self.ui.fileInfoTable.setModel(self.tmodel_info)
        self.ui.fileInfoTable.setTextElideMode(Qt.TextElideMode.ElideNone)
        self.ui.fileInfoTable.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)

        # datalog info table
        self.tmodel_datalog = DatalogSqlQueryModel(self, 13 if isMac else 10)
        self.ui.datalogTable.setModel(self.tmodel_datalog)
        self.ui.datalogTable.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)  # select row only
        self.ui.datalogTable.setItemDelegate(StyleDelegateForTable_List(self.ui.datalogTable))
        self.ui.datalogTable.addAction(self.ui.actionFetchDatalog)

    def getFileMetaData(self):
        """Detailed Info 界面读取文件"""

        metaDataList = fileInformation(self.filePathName)

        return metaDataList

    def updateFileHeader(self):
        """更新 info 页面 """
        # clear old info
        self.tmodel_info.removeRows(0, self.tmodel_info.rowCount())
        horizontalHeader = self.ui.fileInfoTable.horizontalHeader()
        verticalHeader = self.ui.fileInfoTable.verticalHeader()
        horizontalHeader.setVisible(False)
        verticalHeader.setVisible(False)

        for tmpRow in self.getFileMetaData():
            # translate the first element, which is the field names
            qitemRow = [QtGui.QStandardItem(self.tr(ele) if i == 0 else ele) for i, ele in enumerate(tmpRow)]

            if getSetting().language != "English":
                # fix weird font when switch to chinese-s
                qfont = QtGui.QFont(getSetting().font)
                _ = [qele.setData(qfont, Qt.ItemDataRole.FontRole) for qele in qitemRow]
            self.tmodel_info.appendRow(qitemRow)

            # 调整行列的变化
            # horizontalHeader.resizeSection(0, 250)
            for column in range(0, horizontalHeader.count()):
                horizontalHeader.setSectionResizeMode(column, QHeaderView.ResizeMode.ResizeToContents)
                # horizontalHeader.setSectionResizeMode(column, QHeaderView.ResizeMode.Stretch)

            # resize to content to show all texts, then add additional height to each row
            for row in range(self.tmodel_info.rowCount()):
                verticalHeader.setSectionResizeMode(row, QHeaderView.ResizeMode.ResizeToContents)
                newHeight = verticalHeader.sectionSize(row) + 20
                verticalHeader.setSectionResizeMode(row, QHeaderView.ResizeMode.Fixed)
                verticalHeader.resizeSection(row, newHeight)

    def allAction(self):
        """所有槽函数"""
        self.ui.actionOpen.triggered.connect(self.openFile)  # 打开文件

        self.ui.actionAbout.triggered.connect(self.onAbout)  # about 界面

    def enableDragDrop(self):
        """捕获界面抓取文件"""
        for obj in [self.ui.TestList, self.ui.tabControl, self.ui.dataTable]:
            obj.setAcceptDrops(True)
            obj.installEventFilter(self)

    def eventFilter(self, widget, event: QtCore.QEvent):
        """捕获界面抓取文件"""
        # modified from https://stackoverflow.com/questions/18001944/pyqt-drop-event-without-subclassing
        if widget in [self.ui.TestList, self.ui.tabControl, self.ui.dataTable]:
            if (event.type() == QtCore.QEvent.Type.DragEnter):
                if event.mimeData().hasUrls():
                    event.accept()  # must accept the dragEnterEvent or else the dropEvent can't occur !!!
                    return True
                else:
                    event.ignore()
                    return False

            if (event.type() == QtCore.QEvent.Type.Drop):
                if event.mimeData().hasUrls():  # if file or link is dropped
                    urls = event.mimeData().urls()
                    paths = [url.toLocalFile() for url in urls]
                    event.accept()  # doesnt appear to be needed
                    self.filePathName = paths
                    self.updateData()
                    return True
        return False

    def openFile(self):
        # 目前只设置了读取txt文件
        FILE_FILTER = '''All Supported Files (*.txt );;
                            Text Files (*.txt);; 
                                All Files (*.*)'''
        # 使用 QFileDialog 打开文件
        fileName, _ = QFileDialog.getOpenFileName(self, caption="Select New Files To Open", directory=getSetting().recentFolder,
                                                  filter=FILE_FILTER)
        self.filePathName = fileName  # 为后面进行文件的读取进行记录路径
        if self.filePathName:
            # 插入一行数据
            self.updateData()

    def updateData(self):
        """读取到文件路径进行数据的更新"""
        # 更新 detailed info 界面
        self.updateFileHeader()
        # 更新 test select
        self.refreshTestList()


    def refreshTestList(self):
        # test select 更新
        self.completeTestList = ['3300\tOS.ick_en', '3300\tOS.ick', '3300\tOS.iselen', "test\tselect 在这里接口", " self.completeTestList"]
        self.updateModelContent(self.sim_list, self.completeTestList)

    def updateModelContent(self, model, newList):
        """更新内容  test select """
        # clear first
        model.clear()

        for data in newList:
            model.appendRow(QtGui.QStandardItem(data))
    def loadFonts(self):
        """加载字体"""
        for fn in os.listdir(os.path.join("src/fonts")):
            if not fn.endswith(".ttf"): continue
            fontPath = os.path.join("src/fonts", fn)
            fontIdx = QtGui.QFontDatabase.addApplicationFont(fontPath)
            if fontIdx < 0:
                print(f"Font {fn} cannot be loaded to QT")

    def onAbout(self):  # about 关于的设置 gj
        """about 关于的设置 gj"""
        msgBox = QMessageBox(self)
        msgBox.setWindowTitle(self.tr("About"))

        msgBox.setTextFormat(Qt.TextFormat.RichText)

        msgBox.setText("<span style='color:#930DF2;font-size:20px'>CDASystem</span>\
                        <br>{0}: {1}\
                        <br>{2}: 郭靖\
                        <br>{3}: 2976245573@qq.com<br>".format(
            self.tr("Version"),
            Version,
            self.tr("Author"),
            self.tr("Email")))

        msgBox.setInformativeText("{0}:\
            <br><a href='https://gitee.com/guo-jing-123/stdf-viewer/blob/master/README_CN.md'>教程文件README</a>\
            <br>\
            <br><span style='font-size:10px'>{1}</span>".format(
            self.tr("For instructions, please refer to the ReadMe in the repo"),
            self.tr("Disclaimer: This free app is licensed under GPL 3.0, \
                                                                        you may use it free of charge but WITHOUT ANY WARRANTY, \
                                                                        it might contians bugs so use it at your own risk.")))
        appIcon = self.setQIconConfig("App").pixmap(250, 250)
        appIcon.setDevicePixelRatio(2.0)

        ckupdateBtn = msgBox.addButton(self.tr("Check For Updates"), QMessageBox.ButtonRole.ApplyRole)  # middle
        msgBox.addButton(self.tr("OK"), QMessageBox.ButtonRole.NoRole)  # rightmost
        msgBox.exec_()

        if msgBox.clickedButton() == ckupdateBtn:
            self.checkNewVersion()
        else:
            msgBox.close()

    def checkNewVersion(self):
        """检查版本更新 about中"""
        msgBox = QMessageBox(self)
        msgBox.setWindowFlag(Qt.WindowType.FramelessWindowHint)
        msgBox.setTextFormat(Qt.TextFormat.RichText)
        msgBox.setText(self.tr("You're using the latest version."))
        msgBox.exec_()
    def setQIcon(self):
        """设置图标"""
        self.setWindowIcon(self.setQIconConfig("APP"))
        self.ui.actionMerge.setIcon(self.setQIconConfig("Merge"))
        self.ui.actionFailMarker.setIcon(self.setQIconConfig("FailMarker"))
        self.ui.actionExport.setIcon(self.setQIconConfig("Export"))
        self.ui.actionSettings.setIcon(self.setQIconConfig("Settings"))
        self.ui.actionLoad_Session.setIcon(self.setQIconConfig("LoadSession"))
        self.ui.actionSave_Session.setIcon(self.setQIconConfig("SaveSession"))
        self.ui.actionOpen.setIcon(self.setQIconConfig("Open"))
        self.ui.actionAbout.setIcon(self.setQIconConfig("About"))
        self.ui.actionAddFont.setIcon(self.setQIconConfig("AddFont"))
        self.ui.actionToXLSX.setIcon(self.setQIconConfig("Convert"))


        self.ui.tabControl.setTabIcon(tab.Info, self.setQIconConfig("tab_info"))
        self.ui.tabControl.setTabIcon(tab.Trend, self.setQIconConfig("tab_trend"))
        self.ui.tabControl.setTabIcon(tab.Histo, self.setQIconConfig("tab_hist"))
        self.ui.tabControl.setTabIcon(tab.PPQQ, self.setQIconConfig("tab_ppqq"))
        self.ui.tabControl.setTabIcon(tab.Bin, self.setQIconConfig("tab_bin"))
        self.ui.tabControl.setTabIcon(tab.Wafer, self.setQIconConfig("tab_wafer"))
        self.ui.tabControl.setTabIcon(tab.Correlate, self.setQIconConfig("tab_correlation"))

    def setQIconConfig(self, name):
        """设置图标的配置工具 使用的 rust中的QIcon"""
        convert2QIcon = lambda raw: \
            QtGui.QIcon(
                QtGui.QPixmap.fromImage(
                    QtGui.QImage.fromData(raw, format='SVG')))
        return convert2QIcon(rust_stdf_helper.get_icon_src(name))


def run():
    # 设置环境变量 "QT_AUTO_SCREEN_SCALE_FACTOR" 为 "1"，用于自动调整屏幕缩放比例
    os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"

    # 创建一个QApplication对象
    app = QApplication([])

    # 设置应用的样式为'Fusion'
    app.setStyle('Fusion')

    # 设置高DPI支持
    app.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps)

    # 创建主窗口对象
    window = MyWindow()

    # 显示主窗口
    window.show()

    # 运行应用程序的主循环
    sys.exit(app.exec_())


if __name__ == '__main__':
    run()
